/**
  ******************************************************************************
  * @file           : rs71_usb_receiver.cpp
  * @author         : wangyingjie
  * @brief          : None
  * @attention      : None
  * @date           : 2025/6/20
  ******************************************************************************
  */

#include "rs71_usb_receiver.h"

#include <cstdio>
#include <cstring>

RS71UsbReceiver::RS71UsbReceiver(unsigned devType, unsigned devIdx, unsigned chMask, unsigned baud)
    : devType(devType), devIdx(devIdx), chMask(chMask), baud(baud)
{
    memset(rxThreads, 0, sizeof(rxThreads));
}

RS71UsbReceiver::~RS71UsbReceiver()
{
    Stop();
    Close();
}

bool RS71UsbReceiver::init(unsigned devType, unsigned devIdx, unsigned chMask, unsigned baud)
{
    this->devType = devType;
    this->devIdx = devIdx;
    this->chMask = chMask;
    this->baud = baud;
    memset(rxThreads, 0, sizeof(rxThreads));
    return true;
}

bool RS71UsbReceiver::Open()
{
    if (!VCI_OpenDevice(devType, devIdx, 0))
    {
        printf("VCI_OpenDevice failed\n");
        return false;
    }
    printf("VCI_OpenDevice succeeded\n");
    return true;
}

void RS71UsbReceiver::Close()
{
    VCI_CloseDevice(devType, devIdx);
    printf("VCI_CloseDevice\n");
}

bool RS71UsbReceiver::Start()
{
    VCI_INIT_CONFIG config = {
        0,
        0xFFFFFFFF,
        1,
        0,
        static_cast<UCHAR>(baud & 0xff),
        static_cast<UCHAR>(baud >> 8)
    };

    for (int i = 0; i < 4; i++)
    {
        if ((chMask & (1 << i)) == 0)
            continue;

        if (!VCI_InitCAN(devType, devIdx, i, &config))
        {
            printf("VCI_InitCAN(%d) failed\n", i);
            return false;
        }
        if (!VCI_StartCAN(devType, devIdx, i))
        {
            printf("VCI_StartCAN(%d) failed\n", i);
            return false;
        }

        // 启动接收线程
        rxContexts[i].channel = i;
        rxContexts[i].stop = false;
#ifdef WIN32
        rxThreads[i] = (HANDLE)_beginthreadex(NULL, 0, RxThreadFunc, &rxContexts[i], 0, NULL);
#else
        pthread_create(&rxThreads[i], nullptr, RxThreadFunc, &rxContexts[i]);
#endif
    }

    return true;
}

void RS71UsbReceiver::Stop()
{
    for (int i = 0; i < 4; i++)
    {
        if ((chMask & (1 << i)) == 0)
            continue;
        rxContexts[i].stop = true;
#ifdef WIN32
        WaitForSingleObject(rxThreads[i], INFINITE);
        CloseHandle(rxThreads[i]);
#else
        pthread_join(rxThreads[i], nullptr);
#endif
    }
}

std::vector<RS71UsbReceiver::CanFrame> RS71UsbReceiver::GetReceivedData(unsigned channel)
{
    if (channel >= 4)
    {
        return {};
    }
    std::lock_guard<std::mutex> lock(rxContexts[channel].mtx);
    return rxContexts[channel].buffer;
}

THREAD_RETURN RS71UsbReceiver::RxThreadFunc(void *param)
{
    RX_CTX *ctx = static_cast<RX_CTX *>(param);
    VCI_CAN_OBJ can[RX_BUFF_SIZE];

    while (!ctx->stop)
    {
        int cnt = VCI_Receive(3, 0, ctx->channel, can, RX_BUFF_SIZE, RX_WAIT_TIME);
        if (cnt <= 0)
            continue;

        std::lock_guard<std::mutex> lock(ctx->mtx);
        for (int i = 0; i < cnt; ++i)
        {
            CanFrame frame;
            frame.id = can[i].ID;
            frame.timestamp = can[i].TimeStamp;
            frame.data.assign(can[i].Data, can[i].Data + can[i].DataLen);
            ctx->buffer.push_back(frame);
        }
    }

#ifdef WIN32
    _endthreadex(0);
    return 0;
#else
    pthread_exit(0);
#endif
}
